﻿#include "sbaslercameracontrol.h"
#include <QDateTime>


SBaslerCameraControl::SBaslerCameraControl(QObject *parent) : QObject(parent)
{
	dataGray = new uchar[2464 * 2056];
	dateR = new uchar[2464 * 2056];
	dateG = new uchar[2464 * 2056];
	dateB = new uchar[2464 * 2056];
}

SBaslerCameraControl::~SBaslerCameraControl()
{
	deleteAll();
}

void SBaslerCameraControl::initSome()
{
	qDebug() << "SBaslerCameraControl: PylonInitialize initSome";
	PylonInitialize();
}

void SBaslerCameraControl::deleteAll()
{
	//停止采集
	if (m_isOpenAcquire) {
		StopAcquire();
	}
	//关闭摄像头
	CloseCamera();
	//关闭库
	qDebug() << "SBaslerCameraControl deleteAll: PylonTerminate";
	PylonTerminate();
	qDebug() << "SBaslerCameraControl deleteAll: Close";
}

QStringList SBaslerCameraControl::cameras()
{
	return m_cameralist;
}

void SBaslerCameraControl::UpdateCameraList()
{
	CTlFactory& TLFactory = CTlFactory::GetInstance();
	ITransportLayer * pTl = TLFactory.CreateTl("BaslerGigE");
	int n = pTl->EnumerateDevices(devices);
	CInstantCameraArray cameraArray(devices.size());
	if (n == 0) {
		qDebug() << "Cannot find Any camera!";
		return;
	}
	for (int i = 0; i < cameraArray.GetSize(); i++) {
		cameraArray[i].Attach(TLFactory.CreateDevice(devices[i]));
		string sn = cameraArray[i].GetDeviceInfo().GetSerialNumber();
		m_cameralist << QString::fromStdString(sn);
		qDebug() << QString::fromStdString(sn);
	}
}

void SBaslerCameraControl::CopyToImage(CGrabResultPtr pInBuffer, HalconCpp::HObject &OutImage)
{
	try {
		uchar* buff = (uchar*)pInBuffer->GetBuffer();
		int nHeight = pInBuffer->GetHeight();
		int nWidth = pInBuffer->GetWidth();

		memcpy(dataGray, buff, nWidth * nHeight);
		HalconCpp::GenImage1(&OutImage, "byte", nWidth, nHeight, (Hlong)(dataGray));
	}
	catch (GenICam::GenericException &e) {
		qDebug() << "CopyToImage Error:" << QString(e.GetDescription());
	}
}

void SBaslerCameraControl::CopyToImageRGB8(CGrabResultPtr pInBuffer, HalconCpp::HObject &OutImage)
{
	unsigned char *Pointer;
	int width, height;

	height = pInBuffer->GetHeight();
	width = pInBuffer->GetWidth();
	Pylon::PixelType pPixeltype;
	pPixeltype = pInBuffer->GetPixelType();
	Pointer = (uint8_t *)pInBuffer->GetBuffer();
	try
	{
		CImageFormatConverter converter;
		CPylonImage targetImage;
		converter.OutputPixelFormat = Pylon::PixelType::PixelType_RGB8packed;
		converter.Convert(targetImage, pInBuffer);
		//		//m_FramesMutex.lock();

		unsigned char *Pointer = (unsigned char*)targetImage.GetBuffer(); //for Color
//		HalconCpp::GenImageInterleaved(&OutImage, (long)Pointer, "rgb", (HalconCpp::HTuple)width, (HalconCpp::HTuple)height, 0, "byte", 0, 0, 0, 0, 8, 0);
//		//m_FramesMutex.unlock();
//		return;
		for (int i = 0; i < width * height; i++)
		{
			dateR[i] = Pointer[i * 3];
			dateG[i] = Pointer[i * 3 + 1];
			dateB[i] = Pointer[i * 3 + 2];
		}
		HalconCpp::GenImage3(&OutImage, "byte", width, height, (Hlong)dateR, (Hlong)dateG, (Hlong)dateB);
		return;
	}
	catch (HalconCpp::HException e)
	{
		qDebug() << "CopyToImageRGB8 ERROR";
		return;
	}



}
void SBaslerCameraControl::onTimerGrabImage()
{
	if (m_isOpenAcquire) {
		HalconCpp::HObject image;
		HalconCpp::HObject ho_Null;
		HalconCpp::GenEmptyObj(&ho_Null);
		HalconCpp::GenEmptyObj(&image);
		if (m_nImgeBuff < 5)
		{
			GrabImage(image, 1);

			HalconCpp::HTuple hv_n;
			HalconCpp::TestEqualObj(image, ho_Null, &hv_n);
			if (hv_n != 1)//两个Obj不相等
			{
				// Emit the frame received signal

				// Lock the frame queue
				m_FramesMutex.lock();
				// Add frame to queue
				m_Frames.push(image);
				m_nImgeBuff += 1;
				// Unlock frame queue
				m_FramesMutex.unlock();
				emit sigCurrentImage(1);
			}
		}
	}
	QTimer::singleShot(1, this, SLOT(onTimerGrabImage()));
}

int SBaslerCameraControl::OpenCamera(QString cameraSN)
{
	try {
		CTlFactory& TlFactory = CTlFactory::GetInstance();
		DeviceInfoList_t::const_iterator it;
		String_t str = String_t(cameraSN.toStdString().c_str());
		int num = 0;

		for (it = devices.begin(); it != devices.end(); ++it)
		{
			if (it->GetSerialNumber() == str) {
				break;
			}
			num++;
		}

		m_basler.DestroyDevice();
		
		m_basler.Attach(TlFactory.CreateFirstDevice());

		m_basler.Open();
		//获取触发模式
		setFeatureTriggerSourceType("Line1");
		getFeatureTriggerSourceType();
		m_isOpen = true;
	}
	catch (GenICam::GenericException &e) {
		qDebug() << "OpenCamera " << cameraSN << " Error" << QString(e.GetDescription());
		m_isOpen = false;
		return -2;
	}
	return 0;
}

int SBaslerCameraControl::CloseCamera()
{
	if (!m_isOpen) {
		return -1;
	}
	try {
		if (m_basler.IsOpen()) {
			m_basler.DetachDevice();
			m_basler.Close();
		}
	}
	catch (GenICam::GenericException &e) {
		qDebug() << "CloseCamera Error:" << QString(e.GetDescription());
		return -2;
	}
	return 0;
}

void SBaslerCameraControl::setExposureTime(double time)
{
	SetCamera(Type_Basler_ExposureTime, time);
}

int SBaslerCameraControl::getExposureTime()
{
	return QString::number(GetCamera(Type_Basler_ExposureTime)).toInt();
}


int SBaslerCameraControl::getExposureTimeMin()
{
	return DOUBLE_MIN;
}

int SBaslerCameraControl::getExposureTimeMax()
{
	return DOUBLE_MAX;
}

int SBaslerCameraControl::getOffsetX()
{
	return QString::number(GetCamera(Type_Basler_OffsetX)).toInt();
}

int SBaslerCameraControl::getOffsetY()
{
	return QString::number(GetCamera(Type_Basler_OffsetY)).toInt();
}

int SBaslerCameraControl::getCameraWidth()
{
	return QString::number(GetCamera(Type_Basler_Width)).toInt();
}

int SBaslerCameraControl::getCameraHeight()
{
	return QString::number(GetCamera(Type_Basler_Height)).toInt();
}

void SBaslerCameraControl::setOffsetX(double tmpValue)
{
	SetCamera(Type_Basler_OffsetX, tmpValue);
}

void SBaslerCameraControl::setOffsetY(double tmpValue)
{
	SetCamera(Type_Basler_OffsetY, tmpValue);
}

void SBaslerCameraControl::setCameraWidth(double tmpValue)
{
	SetCamera(Type_Basler_Width, tmpValue);
}

void SBaslerCameraControl::setCameraHeight(double tmpValue)
{
	SetCamera(Type_Basler_Height, tmpValue);
}

int SBaslerCameraControl::getGain()
{
	return QString::number(GetCamera(Type_Basler_GainRaw)).toInt();
}

void SBaslerCameraControl::setCameraGain(double tmpValue)
{
	SetCamera(Type_Basler_GainRaw, tmpValue);
}

void SBaslerCameraControl::setFeatureTriggerSourceType(QString type)
{
	//停止采集
	if (m_isOpenAcquire) {
		StopAcquire();
	}
	if (type == "Freerun") {
		SetCamera(Type_Basler_Freerun);
	}
	else if (type == "Line1") {
		SetCamera(Type_Basler_Line1);
	}
}

QString SBaslerCameraControl::getFeatureTriggerSourceType()
{
	INodeMap &cameraNodeMap = m_basler.GetNodeMap();
	CEnumerationPtr  ptrTriggerSel = cameraNodeMap.GetNode("TriggerSelector");
	ptrTriggerSel->FromString("FrameStart");
	CEnumerationPtr  ptrTrigger = cameraNodeMap.GetNode("TriggerMode");
	ptrTrigger->SetIntValue(1);
	CEnumerationPtr  ptrTriggerSource = cameraNodeMap.GetNode("TriggerSource");

	String_t str = ptrTriggerSource->ToString();
	m_currentMode = QString::fromLocal8Bit(str.c_str());
	return m_currentMode;
}

void SBaslerCameraControl::setFeatureTriggerModeType(bool on)
{
	try {
		INodeMap &cameraNodeMap = m_basler.GetNodeMap();
		CEnumerationPtr  ptrTriggerSel = cameraNodeMap.GetNode("TriggerSelector");
		ptrTriggerSel->FromString("FrameStart");
		CEnumerationPtr  ptrTrigger = cameraNodeMap.GetNode("TriggerMode");
		ptrTrigger->SetIntValue(on ? 1 : 0);
	}
	catch (GenICam::GenericException &e) {
		qDebug() << "setFeatureTriggerModeType Error:" << QString(e.GetDescription());
	}
}

bool SBaslerCameraControl::getFeatureTriggerModeType()
{
	try {
		INodeMap &cameraNodeMap = m_basler.GetNodeMap();
		CEnumerationPtr  ptrTriggerSel = cameraNodeMap.GetNode("TriggerSelector");
		ptrTriggerSel->FromString("FrameStart");
		CEnumerationPtr  ptrTrigger = cameraNodeMap.GetNode("TriggerMode");
		return ptrTrigger->GetIntValue() == 1;
	}
	catch (GenICam::GenericException &e) {
		qDebug() << "getFeatureTriggerModeType Error:" << QString(e.GetDescription());
		return false;
	}
}

void SBaslerCameraControl::SetCamera(SBaslerCameraControl::SBaslerCameraControl_Type index, double tmpValue)
{
	try
	{
		INodeMap &cameraNodeMap = m_basler.GetNodeMap();
		switch (index) {
		case Type_Basler_Freerun: {
			CEnumerationPtr  ptrTriggerSel = cameraNodeMap.GetNode("TriggerSelector");
			ptrTriggerSel->FromString("FrameStart");
			CEnumerationPtr  ptrTrigger = cameraNodeMap.GetNode("TriggerMode");
#ifdef Real_Freerun
			ptrTrigger->SetIntValue(0);
#else //Software
			ptrTrigger->SetIntValue(1);
			CEnumerationPtr  ptrTriggerSource = cameraNodeMap.GetNode("TriggerSource");
			ptrTriggerSource->FromString("Software");
#endif
		} break;
		case Type_Basler_Line1: {
			CEnumerationPtr  ptrTriggerSel = cameraNodeMap.GetNode("TriggerSelector");
			ptrTriggerSel->FromString("FrameStart");
			CEnumerationPtr  ptrTrigger = cameraNodeMap.GetNode("TriggerMode");
			ptrTrigger->SetIntValue(1);
			CEnumerationPtr  ptrTriggerSource = cameraNodeMap.GetNode("TriggerSource");
			ptrTriggerSource->FromString("Line1");
		} break;
		case Type_Basler_ExposureTime: {
			// Set the Exposure Time feature.
			// On GigE cameras, the feature is named 'ExposureTimeRaw'.
			// On USB cameras, it is named 'ExposureTime'.

			//            const CFloatPtr exposureTime = cameraNodeMap.GetNode("ExposureTimeRaw");
			//            exposureTime->SetValue(tmpValue);

			m_exposureTime = GetIntegerParameter(cameraNodeMap.GetNode("ExposureTime"));
			
			if (!m_exposureTime.IsValid())
			{
				m_exposureTime = GetIntegerParameter(cameraNodeMap.GetNode("ExposureTimeRaw"));
			}

			m_exposureTime.SetValue(tmpValue);
		} break;
		case Type_Basler_GainRaw: {

			// Set the Gain feature.
			// On GigE cameras, the feature is named 'GainRaw'.
			// On USB cameras, it is named 'Gain'

			//            const CFloatPtr cameraGen = cameraNodeMap.GetNode("GainRaw");
			//            cameraGen->SetValue(tmpValue);


			m_gain = GetIntegerParameter(cameraNodeMap.GetNode("Gain"));
			if (!m_gain.IsValid())
			{
				m_gain = GetIntegerParameter(cameraNodeMap.GetNode("GainRaw"));
			}
			m_gain.SetValue(tmpValue);
		} break;
		case Type_Basler_AcquisitionFrameRateAbs: {
			const CBooleanPtr frameRate = cameraNodeMap.GetNode("AcquisitionFrameRateEnable");
			frameRate->SetValue(TRUE);
			const CFloatPtr frameRateABS = cameraNodeMap.GetNode("AcquisitionFrameRateAbs");
			frameRateABS->SetValue(tmpValue);
		} break;
		case Type_Basler_Width: {
			const CIntegerPtr widthPic = cameraNodeMap.GetNode("Width");
			widthPic->SetValue(tmpValue);
		} break;
		case Type_Basler_Height: {
			const CIntegerPtr heightPic = cameraNodeMap.GetNode("Height");
			heightPic->SetValue(tmpValue);
		} break;
		case Type_Basler_LineSource: {
			CEnumerationPtr  ptrLineSource = cameraNodeMap.GetNode("LineSource");
			ptrLineSource->SetIntValue(2);
		} break;
		case Type_Basler_OffsetX: {
			const CIntegerPtr  OffsetX = cameraNodeMap.GetNode("OffsetX");
			OffsetX->SetValue(tmpValue);
		} break;
		case Type_Basler_OffsetY: {
			const CIntegerPtr  OffsetY = cameraNodeMap.GetNode("OffsetY");
			OffsetY->SetValue(tmpValue);
		} break;
		default:
			break;
		}
	}
	catch (GenICam::GenericException &e) {
		qDebug() << "SetCamera Error:" << QString(e.GetDescription());
	}

}

double SBaslerCameraControl::GetCamera(SBaslerCameraControl::SBaslerCameraControl_Type index)
{
	try
	{
		INodeMap &cameraNodeMap = m_basler.GetNodeMap();
		switch (index) {
		case Type_Basler_ExposureTime: {
			//            const CFloatPtr exposureTime = cameraNodeMap.GetNode("ExposureTimeAbs");
			//            return exposureTime->GetValue();

			// Get the Exposure Time feature.
			// On GigE cameras, the feature is named 'ExposureTimeRaw'.
			// On USB cameras, it is named 'ExposureTime'.
			m_exposureTime = GetIntegerParameter(cameraNodeMap.GetNode("ExposureTime"));
			if (!m_exposureTime.IsValid())
			{
				m_exposureTime = GetIntegerParameter(cameraNodeMap.GetNode("ExposureTimeRaw"));
			}
			return m_exposureTime.GetValue();
		} break;
		case Type_Basler_GainRaw: {

			//            const CFloatPtr cameraGen = cameraNodeMap.GetNode("Gain");
			//            return cameraGen->GetValue();

			// Get the Gain feature.
			// On GigE cameras, the feature is named 'GainRaw'.
			// On USB cameras, it is named 'Gain'.
			m_gain = GetIntegerParameter(cameraNodeMap.GetNode("Gain"));
			if (!m_gain.IsValid())
			{
				m_gain = GetIntegerParameter(cameraNodeMap.GetNode("GainRaw"));
			}
			return m_gain.GetValue();
		} break;
		case Type_Basler_AcquisitionFrameRateAbs: {
			const CBooleanPtr frameRate = cameraNodeMap.GetNode("AcquisitionFrameRateEnable");
			frameRate->SetValue(TRUE);
			const CFloatPtr frameRateABS = cameraNodeMap.GetNode("AcquisitionFrameRateAbs");
			return frameRateABS->GetValue();
		} break;
		case Type_Basler_Width: {
			const CIntegerPtr widthPic = cameraNodeMap.GetNode("Width");
			return widthPic->GetValue();
		} break;
		case Type_Basler_Height: {
			const CIntegerPtr heightPic = cameraNodeMap.GetNode("Height");
			return heightPic->GetValue();
		} break;
		case Type_Basler_OffsetX: {
			CIntegerPtr  OffsetX = cameraNodeMap.GetNode("OffsetX");
			return OffsetX->GetValue();
		} break;
		case Type_Basler_OffsetY: {
			CIntegerPtr  OffsetY = cameraNodeMap.GetNode("OffsetY");
			return OffsetY->GetValue();
		} break;
		default:
			return -1;
			break;
		}
	}
	catch (GenICam::GenericException &e) {
		qDebug() << "GetCamera Error:" << QString(e.GetDescription());
	}

}

long SBaslerCameraControl::StartAcquire()
{
	m_isOpenAcquire = true;
	try {
		qDebug() << "SBaslerCameraControl StartAcquire" << m_currentMode;
		if (m_currentMode == "Freerun") {
			m_basler.StartGrabbing(GrabStrategy_LatestImageOnly, GrabLoop_ProvidedByInstantCamera);
		}
		else if (m_currentMode == "Software") {
			m_basler.StartGrabbing(GrabStrategy_LatestImageOnly);
			onTimerGrabImage();
		}
		else if (m_currentMode == "Line1") {
			m_basler.StartGrabbing(GrabStrategy_OneByOne);
			onTimerGrabImage();
		}
		else if (m_currentMode == "Line2") {
			m_basler.StartGrabbing(GrabStrategy_OneByOne);
		}
	}
	catch (GenICam::GenericException &e) {
		//        OutputDebugString(L"StartAcquire error:");
		qDebug() << "StartAcquire Error:" << QString(e.GetDescription());
		return -2;
	}
	return 0;
}

long SBaslerCameraControl::StopAcquire()
{
	m_isOpenAcquire = false;
	qDebug() << "SBaslerCameraControl StopAcquire";
	try {
		if (m_basler.IsGrabbing()) {
			m_basler.StopGrabbing();
		}
	}
	catch (GenICam::GenericException &e) {
		//      OutputDebugString(LPCWSTR(e.GetDescription()));
		qDebug() << "StopAcquire Error:" << QString(e.GetDescription());
		return -2;
	}
	return 0;
}

long SBaslerCameraControl::GrabImage(HalconCpp::HObject &Hobj, int timeout)
{
	try {
		if (!m_basler.IsGrabbing()) {
			StartAcquire();
		}
		CGrabResultPtr ptrGrabResult;
		if (m_currentMode == "Freerun") {
		}
		else if (m_currentMode == "Software") {
			if (m_basler.WaitForFrameTriggerReady(1000, TimeoutHandling_Return)) {
				m_basler.ExecuteSoftwareTrigger();
				m_basler.RetrieveResult(timeout, ptrGrabResult, TimeoutHandling_Return);
			}
		}
		else if (m_currentMode == "Line1") {
			m_basler.RetrieveResult(timeout, ptrGrabResult, TimeoutHandling_Return);
		}
		else if (m_currentMode == "Line2") {
			m_basler.RetrieveResult(timeout, ptrGrabResult, TimeoutHandling_Return);
		}
		if (ptrGrabResult == NULL) {
			return -5;
		}
		if (ptrGrabResult->GrabSucceeded()) {
			nIndex++;
			if (!ptrGrabResult.IsValid()) { OutputDebugString(L"GrabResult not Valid Error\n"); return -1; }
			EPixelType pixelType = ptrGrabResult->GetPixelType();
			switch (pixelType) {
			case PixelType_Mono8: {
				CopyToImage(ptrGrabResult, Hobj);

			} break;
			case PixelType_BayerRG8: {
				CopyToImageRGB8(ptrGrabResult, Hobj);
			}  break;
			default:
				qDebug() << "what: default";
				break;
			}
		}
		else {
			qDebug() << "Grab Error!!!";
			//            OutputDebugString(L"Grab Error!!!");
			return -3;
		}
	}
	catch (GenICam::GenericException &e) {
		//        OutputDebugString(L"GrabImage Error\n");
		qDebug() << "GrabImage Error:" << QString(e.GetDescription());
		//        OutputDebugString((e.GetDescription()));
		return -2;
	}
	catch (...) {
		OutputDebugString(L"ZP 11 Shot GetParam Try 12 No know Error\n");
		return -1;
	}
	return 0;
}


Pylon::CIntegerParameter SBaslerCameraControl::GetIntegerParameter(GenApi::INode* pNode) const
{
	Pylon::CFloatParameter parameterFloat(pNode);
	Pylon::CIntegerParameter parameterInteger;

	// Is this a float feature?
	if (parameterFloat.IsValid())
	{
		// Get the alias.
		// If it doesn't exist, return an empty parameter.
		parameterFloat.GetAlternativeIntegerRepresentation(parameterInteger);
	}
	else
	{
		// Convert the node to an integer parameter.
		// If conversion isn't possible, return an empty parameter.
		parameterInteger.Attach(pNode);
	}

	return parameterInteger;
}

HalconCpp::HObject SBaslerCameraControl::GetFrame()
{
	// Lock the frame queue
	m_FramesMutex.lock();
	// Pop frame from queue
	HalconCpp::HObject res;
	if (!m_Frames.empty())
	{
		res = m_Frames.front();
		m_Frames.pop();
	}
	// Unlock frame queue
	m_FramesMutex.unlock();
	return res;
}

void SBaslerCameraControl::ClearFrameQueue()
{
	// Lock the frame queue
	m_FramesMutex.lock();
	// Clear the frame queue and release the memory
	std::queue<HalconCpp::HObject> empty;
	std::swap(m_Frames, empty);
	// Unlock the frame queue
	m_FramesMutex.unlock();
}
